package pri.damai.xiaowu.auth.security.handle;

import org.springframework.data.redis.core.RedisTemplate;
import pri.damai.xiaowu.auth.security.model.UserInfo;
import pri.damai.xiaowu.auth.utils.HttpUtil;
import pri.damai.xiaowu.auth.vo.LoginSuccessVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import pri.damai.xiaowu.common.core.util.DateUtils;
import pri.damai.xiaowu.common.core.vo.ResultVO;
import pri.damai.xiaowu.common.security.config.SecurityUtil;
import pri.damai.xiaowu.common.security.config.XiaoWuSecurityProperties;
import pri.damai.xiaowu.common.security.constant.AuthConstant;
import pri.damai.xiaowu.common.security.model.AuthRole;
import pri.damai.xiaowu.common.security.token.RuiRuanAccessToken;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 认证成功处理器
 * @Desc
 * @Author DaMai
 * @Date 2021/7/15 10:53
 * 但行好事，莫问前程。
 */
@Component
public class RuiRuanAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    ApplicationContext context;
    @Resource
    SecurityUtil securityUtil;
    @Resource
    RedisTemplate<String, Object> redisTemplate;
    @Resource
    XiaoWuSecurityProperties securityProperties;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException {

        UserInfo userInfo = (UserInfo) authentication.getPrincipal();

        if (Objects.isNull(userInfo)) {
            throw new AuthenticationServiceException("认证失败。userInfo is null");
        }

        ResultVO<LoginSuccessVO> resultVO = this.convertToResultVo(userInfo);

        // 处理返回值
        HttpUtil.respJson(httpServletResponse,resultVO);
    }

    /**
     * 获取存放Token的RedisKey
     * @apiNote [附加描述]
     * @param userId 用户Id
     * @return java.lang.String
     * @author DaMai
     * @date 2021/10/29 10:43
     */
    private String getTokenRedisKey(String userId) {
        return securityProperties.getTokenRedisKey() + userId;
    }

    /**
     * 处理登录返回值
     * @apiNote [附加描述]
     * @param userInfo 用户信息
     * @return com.ruiruan.pre.common.core.vo.ResultVO<com.ruiruan.ruiruanpreauth.vo.LoginSuccessVO>
     * @author DaMai
     * @date 2021/10/29 10:44
     */
    private ResultVO<LoginSuccessVO> convertToResultVo(UserInfo userInfo) {

        // 创建 Token 负载
        HashMap<String, Object> claims = new HashMap<>();
        String roles = userInfo.getAuthorities()
                .stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(","));
        String userId = userInfo.getId();

        claims.put(AuthConstant.USER_ID_KEY, userId);
        claims.put(AuthConstant.USER_NAME_KEY, userInfo.getOrgName());
        claims.put(AuthConstant.ORG_ID_KEY, userInfo.getOrgId());
        claims.put(AuthConstant.ORG_NAME_KEY, userInfo.getOrgName());
        claims.put(AuthConstant.ROLES_STRING_KEY, roles);

        RuiRuanAccessToken accessToken = securityUtil.createAccessToken(claims,false);

        // 处理 token
        redisTemplate.opsForValue()
                .set(getTokenRedisKey(userId), accessToken, securityProperties.getExpiration(), TimeUnit.SECONDS);

        List<AuthRole> roleNameList = userInfo.getRoleList();

        LoginSuccessVO loginSuccessVO = new LoginSuccessVO();
        loginSuccessVO.setAvatarUrl(userInfo.getAvatarUrl())
                .setGender(userInfo.getGender())
                .setOrgId(userInfo.getOrgId())
                .setRoleNames(roleNameList)
                .setToken(accessToken.getToken())
                .setPhone(userInfo.getPhone())
                .setUserId(userId)
                .setUsername(userInfo.getUsername())
                .setOrgName(userInfo.getOrgName())
                .setRegisterDate(DateUtils.formatDateTime(LocalDateTime.now(), DateUtils.YYYY_MM_DD));

        return ResultVO.success(loginSuccessVO);
    }
}
